package nyu.edu.database.operation;

public class Operation {

	private final OperationType myOperationType;
	private final int transactionId;
	private final int dataId;
	private final int dataValue;
	private final int siteId;
	private boolean isExecuted;

	public Operation(OperationType myOperationType, int transactionId,
			int dataId, int dataValue, int siteId) {
		super();
		this.myOperationType = myOperationType;
		this.transactionId = transactionId;
		this.dataId = dataId;
		this.dataValue = dataValue;
		this.siteId = siteId;
		this.isExecuted = false;
	}

	/**
	 * @author Yuri Soussov
	 * @param operationString
	 *            - a line of input from the terminal
	 * @return - an array containing the operations in that line
	 */
	public static Operation[] getOperationsFromInputString(
			String operationString) {
		String[] myStrings = operationString.split(";");
		Operation[] toReturn = new Operation[myStrings.length];
		for (int y = 0; y < myStrings.length; y++) {
			String x = myStrings[y].trim();
			String[] tempArray = x.split("\\("); // put in error checking
			String operationType = tempArray[0];
			String operationFunctions = tempArray[1];
			OperationType type = OperationType.getTypeFromString(operationType);
			switch (type) {
			case BEGIN:
				toReturn[y] = createBeginOperation(operationFunctions);
				continue;
			case BEGINRO:
				toReturn[y] = createBeginROOperation(operationFunctions);
				continue;
			case READ:
				toReturn[y] = createReadOperation(operationFunctions);
				continue;
			case WRITE:
				toReturn[y] = createWriteOperation(operationFunctions);
				continue;
			case DUMP:
				toReturn[y] = createDumpOperation(operationFunctions);
				continue;
			case END:
				toReturn[y] = createEndOperation(operationFunctions);
				continue;
			case RECOVER:
				toReturn[y] = createRecoverOperation(operationFunctions);
				continue;
			case FAIL:
				toReturn[y] = createFailOperation(operationFunctions);
				continue;
			}
		}
		return toReturn;

	}

	/*****************************************************************************************************
	 * Begin private functions to create different operation types from the *
	 * tail of the input string *
	 *****************************************************************************************************/

	private static Operation createRecoverOperation(String operationFunctions) {
		return new Operation(OperationType.RECOVER, -1, -1, -1,
				Integer.parseInt(operationFunctions.substring(0, 1)));
	}

	private static Operation createFailOperation(String operationFunctions) {
		return new Operation(OperationType.FAIL, -1, -1, -1,
				Integer.parseInt(operationFunctions.substring(0, 1)));
	}

	private static Operation createEndOperation(String operationFunctions) {
		return new Operation(OperationType.END,
				Integer.parseInt(operationFunctions.substring(1, 2)), -1, -1,
				-1);
	}

	private static Operation createDumpOperation(String operationFunctions) {
		if (operationFunctions.contains("x")) {
			return new Operation(OperationType.DUMP, -1,
					Integer.parseInt(operationFunctions.substring(1, 2)), -1,
					-1);
		} else {
			if (operationFunctions.charAt(0) != ')') {
				return new Operation(OperationType.DUMP, -1, -1, -1,
						Integer.parseInt(operationFunctions.substring(0, 1)));
			} else {
				return new Operation(OperationType.DUMP, -1, -1, -1, -1);
			}
		}
	}

	private static Operation createWriteOperation(String operationFunctions) {
		String[] splitString = operationFunctions.split(",");
		int transactionId = Integer.parseInt(splitString[0].trim().substring(1,
				2));
		int variableId = Integer
				.parseInt(splitString[1].trim().substring(1, 2));
		int value = Integer.parseInt(splitString[2].trim().split("\\)")[0]);
		return new Operation(OperationType.WRITE, transactionId, variableId,
				value, -1);
	}

	private static Operation createReadOperation(String operationFunctions) {
		String[] splitString = operationFunctions.split(",");
		int transactionId = Integer.parseInt(splitString[0].trim().substring(1,
				2));
		int variableId = Integer
				.parseInt(splitString[1].trim().substring(1, 2));
		return new Operation(OperationType.READ, transactionId, variableId, -1,
				-1);
	}

	private static Operation createBeginROOperation(String operationFunctions) {
		return new Operation(OperationType.BEGINRO,
				Integer.parseInt(operationFunctions.substring(1, 2)), -1, -1,
				-1);
	}

	private static Operation createBeginOperation(String operationFunctions) {
		return new Operation(OperationType.BEGIN,
				Integer.parseInt(operationFunctions.substring(1, 2)), -1, -1,
				-1);
	}

	/*****************************
	 * Begin Getters And Setters *
	 *****************************/

	public boolean isExecuted() {
		return isExecuted;
	}

	public void setExecuted(boolean isExecuted) {
		this.isExecuted = isExecuted;
	}

	public OperationType getMyOperationType() {
		return myOperationType;
	}

	public int getTransactionId() {
		return transactionId;
	}

	public int getDataId() {
		return dataId;
	}

	public int getDataValue() {
		return dataValue;
	}

	@Override
	public String toString() {
		return "Operation [myOperationType=" + myOperationType
				+ ", transactionId=" + transactionId + ", dataId=" + dataId
				+ ", dataValue=" + dataValue + ", siteId=" + siteId
				+ ", isExecuted=" + isExecuted + "]";
	}

}
